require 'erb'

class GenTupel

  attr_reader(:size, :total)

  def initialize(size, total_build)
    @size = size
    @total = total_build
    erb = ERB.new(File.open('template.tmp').readlines.join)
    File.open("Tuple#{ size }.java", "w") do |file|
      file.puts(erb.result(binding))
    end
  end

  def size_range(&block)
    (1 .. @size).map(&block)
  end

  # 工具方法

  def array_product(a, b)
    alen, blen = a.size, b.size
    a.flat_map { |e| [e] * blen }.zip(b * alen)
  end

  def _setAt(index)
    types = size_range { |i| i == index ? 'X' : "T#{ i }" }
    values = size_range { |i| i == index ? 'arg' : "value#{ i }" }
    "public <X> Tuple#{ @size }<#{ types.join(', ') }> setAt#{ index }(final X arg) { return new Tuple#{ @size }<>(#{ values.join(',') }); }"
  end

  def _removeAt_generic_types(arr)
    arr.map { |i| "T#{ i }" }.join(', ')
  end

  def _removeAt_values(arr)
    arr.map { |i| "value#{ i }" }.join(', ')
  end

  def _removeAt(index)
    args = size_range(&:to_s)
    args.delete_at(index - 1)
    "public Tuple#{ @size - 1 }<#{ _removeAt_generic_types(args) }> removeAt#{ index }() { return new Tuple#{ @size - 1 }<>(#{ _removeAt_values(args) }); }"
  end

  def _insertArgsAt(index, arg_cnt)
    ts = size_range { |i| "T#{ i }" }
    xs = (1 .. arg_cnt).to_a.map { |i| "X#{ i }" }
    types = ts.insert(index, *xs)
    values = size_range { |i| "value#{ i }" }
    args = (1 .. arg_cnt).to_a.map { |i| "arg#{ i }" }
    args_and_values = values.insert(index, *args)
    final_x_args = (1 .. arg_cnt).to_a.map { |i| "final X#{ i } arg#{ i }" }
    "public <#{ xs.join(', ') }> Tuple#{ @size + arg_cnt }<#{ types.join(', ') }> insertArgsAt#{ index }(#{ final_x_args.join(', ') }) { return new Tuple#{ @size + arg_cnt }<>(#{ args_and_values.join(', ')}); }"
  end

  def _insertTupleAt(index, tuple_size)
    ts = size_range { |i| "T#{ i }" }
    xs = (1 .. tuple_size).to_a.map { |i| "X#{ i }" }
    types = ts.insert(index, *xs)
    values = size_range { |i| "value#{ i }" }
    tuple_properties = (1 .. tuple_size).to_a.map { |i| "tuple.getValue#{ i }()" }
    values_and_tuple_properties = values.insert(index, *tuple_properties)
    "public <#{ xs.join(', ') }> Tuple#{ @size + tuple_size }<#{ types.join(', ') }> insertTupleAt#{ index }(final Tuple#{ tuple_size }<#{ xs.join(', ') }> tuple) { return new Tuple#{ @size + tuple_size }<>(#{ values_and_tuple_properties.join(', ')}); }"
  end

  def _case_return_value_break
    (1 .. @size).map { |i| "case #{ i }: return value#{ i };" }
  end

  def _public_T_getValue
    size_range { |i| "public T#{ i } getValue#{ i }() { return value#{ i }; }" }
  end

  # 下面的的是ERB中使用的方法

  def types
    size_range { |i| "T#{ i }" }.join(', ')
  end

  def private_final_T_value
    size_range { |i| "private final T#{ i } value#{ i };" }.join("\n\t")
  end

  def final_T_arg
    size_range { |i| "final T#{ i } arg#{ i }" }.join(', ')
  end

  def this_dot_value_eq_arg
    size_range { |i| "this.value#{ i } = arg#{ i };" }.join("\n\t\t")
  end

  def arg
    size_range { |i| "arg#{ i }" }.join(', ')
  end

  def xs
    Array.new(@size, 'X').join(', ')
  end

  def array
    size_range { |i| "array[#{ i - 1 }]" }.join(', ')
  end

  def setAt
    size_range { |i| _setAt(i) }.join("\n\t")
  end

  def removeAt
    @size <= 1 ? '' : size_range { |i| _removeAt(i) }.join("\n\t")
  end

  def insertArgsAt
    @total - @size <= 0 ? '' : array_product((0 .. @size).to_a, (1 .. @total - @size).to_a).map { |arr| _insertArgsAt(*arr) }.sort { |a, b| -(a <=> b) }.join("\n\t")
  end

  def insertTupleAt
    @total - @size <= 0 ? '' : array_product((0 .. @size).to_a, (1 .. @total - @size).to_a).map { |arr| _insertTupleAt(*arr) }.sort { |a, b| -(a <=> b) }.join("\n\t")
  end

  def case_return_value_break
    _case_return_value_break.join("\n\t\t\t")
  end

  def values
    size_range { |i| "value#{ i }" }.join(', ')
  end

  def public_T_getValue
    _public_T_getValue.join
  end
end

(1 .. 10).each { |i| GenTupel.new(i, 10) }

